﻿using System.Collections.Generic;

namespace Codemonk.Common.ObjectModel
{
    public abstract class TransactionObject : ITransactionObject
    {
        public abstract void Commit();
    }

    public sealed class TransactionObject<T> : TransactionObject, ITransactionObject
    {
        private T oldValue;

        public TransactionObject(T obj) { oldValue = obj; }

        /// <summary>
        /// 返回上一个值
        /// </summary>
        private Stack<T> undo = new Stack<T>(32);
        /// <summary>
        /// 使用最后设置的值
        /// </summary>
        private Stack<T> redo = new Stack<T>(32);

        public override void Commit()
        {
            oldValue = CurrentValue;
            undo.Clear();
            redo.Clear();
        }

        public T CurrentValue
        {
            get
            {
                if (undo.Count == 0) return oldValue;
                return undo.Peek();
            }
        }

        public static implicit operator T(TransactionObject<T> value)
        {
            return value == null ? default(T) : value.oldValue;
        }

        public static implicit operator TransactionObject<T>(T value)
        {
            return new TransactionObject<T>(value);
        }

        /// <summary>
        /// 设置事物对象的新值
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        /// <returns></returns>
        public static TransactionObject<T> operator +(TransactionObject<T> lhs, T rhs)
        {
            if (lhs == null) lhs = new TransactionObject<T>(rhs);
            else
                lhs.undo.Push(rhs);
            TransactionContextManager.CurrentContext.Add(lhs);
            return lhs;
        }
        /// <summary>
        /// 使用上一次回退的值
        /// </summary>
        /// <param name="lhs"></param>
        /// <returns></returns>
        public static TransactionObject<T> operator ++(TransactionObject<T> lhs)
        {
            if (lhs.redo.Count == 0) return lhs;
            var value = lhs.redo.Pop();
            lhs.undo.Push(value);
            return lhs;
        }
        /// <summary>
        /// 使用上一次设置的值
        /// </summary>
        /// <param name="lhs"></param>
        /// <returns></returns>
        public static TransactionObject<T> operator --(TransactionObject<T> lhs)
        {
            if (lhs.undo.Count == 0) return lhs;
            var value = lhs.undo.Pop();
            lhs.redo.Push(value);
            return lhs;
        }
    }
}
